
#include "stdafx.h"
#include "util.h"

#ifdef _DEBUG

#define DEBUG_NEW new( _NORMAL_BLOCK, __FILE__, __LINE__ )
#define new DEBUG_NEW

#endif
 

namespace banknamespace
{
	

	///// move from main class
	void buildProjectionMatrix(float *m, float fov, float aspect, float znear, float zfar)
	{
	  float xymax = znear * tan(fov * 3.1416f / 360.0f);
	  float ymin = -xymax;
	  float xmin = -xymax;

	  float width = xymax - xmin;
	  float height = xymax - ymin;

	  float depth = zfar - znear;
	  float q = -(zfar + znear) / depth;
	  float qn = -2 * (zfar * znear) / depth;

	  float w = 2 * znear / width;
	  w = w / aspect;
	  float h = 2 * znear / height;

	  m[0]  = w;
	  m[1]  = 0;
	  m[2]  = 0;
	  m[3]  = 0;

	  m[4]  = 0;
	  m[5]  = h;
	  m[6]  = 0;
	  m[7]  = 0;

	  m[8]  = 0;
	  m[9]  = 0;
	  m[10] = q;
	  m[11] = -1;

	  m[12] = 0;
	  m[13] = 0;
	  m[14] = qn;
	  m[15] = 0;
	}



	//void matrixTranspose(float* mat)
	//{
	//	//in-place transpose
	//	std::swap(mat[1],mat[4]);
	//	std::swap(mat[2],mat[8]);
	//	std::swap(mat[3],mat[12]);
	//	std::swap(mat[6],mat[9]);
	//	std::swap(mat[7],mat[13]);
	//	std::swap(mat[11],mat[14]);
	//}

	
	void matrixMult33(const float* lhs, const float* rhs, float* result)
	{
		//assume that the arguments are valid float[16] buffers
		result[0] = lhs[0]*rhs[0] + lhs[1]*rhs[3] + lhs[2]*rhs[6];
		result[1] = lhs[0]*rhs[1] + lhs[1]*rhs[4] + lhs[2]*rhs[7];
		result[2] = lhs[0]*rhs[2] + lhs[1]*rhs[5] + lhs[2]*rhs[8];

		result[3] = lhs[3]*rhs[0] + lhs[4]*rhs[3] + lhs[5]*rhs[6];
		result[4] = lhs[3]*rhs[1] + lhs[4]*rhs[4] + lhs[5]*rhs[7];
		result[5] = lhs[3]*rhs[2] + lhs[4]*rhs[5] + lhs[5]*rhs[8];

		result[6] = lhs[6]*rhs[0] + lhs[7]*rhs[3] + lhs[8]*rhs[6];
		result[7] = lhs[6]*rhs[1] + lhs[7]*rhs[4] + lhs[8]*rhs[7];
		result[8] = lhs[6]*rhs[2] + lhs[7]*rhs[5] + lhs[8]*rhs[8];
	}

	
	void fromEulerAngles( float pitch, float yaw, float roll, float* res )
	{
		float fCos, fSin;

		fCos = cos(yaw);
		fSin = sin(yaw);
		float fkYMat[] = 
		{
			fCos, 0.0f, fSin,
			0.0f, 1.0f, 0.0f, 
			-fSin, 0.0f, fCos
		};

		fCos = cos(pitch);
		fSin = sin(pitch);
		float fkXMat[] = 
		{
			1.0f, 0.0f, 0.0f, 
			0.0f, fCos, -fSin,
			0.0f, fSin, fCos, 
		};

		fCos = cos(roll);
		fSin = sin(roll);
		float fkZMat[] = 
		{
			fCos, -fSin, 0.0f, 
			fSin, fCos, 0.0f,
			0.0f, 0.0f, 1.0f, 
		};

		//Mat4 tmp = kZMat.matrixMult(kXMat);
		//tmp = tmp.matrixMult(kYMat);
		float result[9];
		float result2[9];
		/*kZMat.matrixMult33(kXMat);
		tmp = tmp.matrixMult33(kYMat);*/


		matrixMult33(fkXMat, fkZMat, result);
		matrixMult33(fkYMat, result, result2);
		//return Mat4(tmp.getValue());
		
		for (int i = 0; i < 9; ++i)
		{
			res[i] = result2[i];
		}
	}

	//GLuint LoadMemoryTexture( unsigned char* pixels, int width, int height )
	//{
	//	    //int width,height,nChannels;
	//	    //unsigned char* pixels = stbi_load(szFilePath, &width, &height, &nChannels, 4);
	//	    // ... process data if not NULL ... 
	//	    // ... x = width, y = height, n = # 8-bit components per pixel ...
	//	    // ... replace '0' with '1'..'4' to force that many components per pixel
	//	    // ... but 'n' will always be the number that it would have been if you said 0
	//		//CONST wchar *lp
	//		if (!pixels)
	//		{
	//			//MessageBox(NULL, L"File load error", L"Error", 0);
	//			return 0;
	//		}

	//		GLuint idTexture;
	//		glGenTextures(1, &idTexture);
	//		glBindTexture( GL_TEXTURE_2D, idTexture );

	//		glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
	//		//glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
	//		glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
	//		//glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
	//		//glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
	//		glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels );
	//		
	//		glGenerateMipmap( GL_TEXTURE_2D );

	//	    //delete[] pixels;
	//		
	//		return idTexture;
	//}

	//GLuint LoadTexture( const char* szFilePath )
	//{
	//	    int width,height,nChannels;
	//	    unsigned char* pixels = stbi_load(szFilePath, &width, &height, &nChannels, 4);
	//	    // ... process data if not NULL ... 
	//	    // ... x = width, y = height, n = # 8-bit components per pixel ...
	//	    // ... replace '0' with '1'..'4' to force that many components per pixel
	//	    // ... but 'n' will always be the number that it would have been if you said 0
	//		//CONST wchar *lp
	//		if (!pixels)
	//		{
	//			//MessageBox(NULL, L"File load error", L"Error", 0);
	//			return 0;
	//		}

	//		GLuint idTexture;
	//		glGenTextures(1, &idTexture);
	//		glBindTexture( GL_TEXTURE_2D, idTexture );

	//		glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
	//		//glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
	//		glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
	//		//glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
	//		//glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
	//		glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels );
	//		
	//		glGenerateMipmap( GL_TEXTURE_2D );

	//	    stbi_image_free(pixels);
	//		
	//		return idTexture;
	//}

	//GLuint LoadTexture( const char* szFilePath )
	//{
	//	    //int width,height,nChannels;

	//		ilInit();
	//		ilEnable( IL_ORIGIN_SET );
	//		ilOriginFunc( IL_ORIGIN_UPPER_LEFT );

	//		ILuint idImage = ilGenImage();
	//		ilBindImage( idImage );
	//		
	//		size_t requiredSize = 0;
	//		::mbstowcs_s(&requiredSize,NULL,0,szFilePath,0);
	//		wchar_t* w_szTexturePath = new wchar_t[requiredSize + 1];
	//		::mbstowcs_s(&requiredSize, w_szTexturePath,requiredSize + 1, szFilePath,requiredSize);

	//		ilLoadImage( w_szTexturePath );

	//		delete w_szTexturePath;

	//		if (IL_NO_ERROR != ilGetError())
	//		{
	//			return 0;
	//		}

	//		ILuint width = ilGetInteger( IL_IMAGE_WIDTH );
	//		ILuint height = ilGetInteger( IL_IMAGE_HEIGHT );
	//		ILuint format = ilGetInteger( IL_IMAGE_FORMAT );
	//		ILuint type = ilGetInteger( IL_IMAGE_TYPE );
	//		ILuint nChannels = ilGetInteger( IL_IMAGE_CHANNELS );

	//		GLuint idTexture;
	//		glGenTextures(1, &idTexture);
	//		glBindTexture( GL_TEXTURE_2D, idTexture );

	//		glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
	//		glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
	//		//glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
	//		glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
	//		//glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
	//		//glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
	//		glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, format, type, ilGetData() );
	//		
	//		glGenerateMipmap( GL_TEXTURE_2D );

	//	    ilDeleteImage( idImage );
	//		
	//		return idTexture;
	//}

	

	void DrawOrigin (float length)
	{
		
		glPushAttrib( GL_COLOR_BUFFER_BIT | GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT );

		glDisable( GL_BLEND );
		glDisable( GL_TEXTURE_2D );
		glDisable( GL_DEPTH_TEST );

		glBegin( GL_LINES );
		{
			// X Axis
			glColor3f(1.0f, 0.0f, 0.0f);
			glVertex3f(0,0,0);
			glColor3f(1.0f, 0.0f, 0.0f);
			glVertex3f(length,0,0);

			// Y Axis
			glColor3f(0.0f, 1.0f, 0.0f);
			glVertex3f(0,0,0);
			glColor3f(0.0f, 1.0f, 0.0f);
			glVertex3f(0,length,0);

			// Z Axis
			glColor3f(0.0f, 0.0f, 1.0f);
			glVertex3f(0,0,0);
			glColor3f(0.0f, 0.0f, 1.0f);
			glVertex3f(0,0,length);
		}
		glEnd();

		glPopAttrib();
	}

	wchar_t* CharToWChar(char* ch)
	{
		size_t requiredSize = 0;
		::mbstowcs_s(&requiredSize,NULL,0,ch,0);
		wchar_t* w_ch = new wchar_t[requiredSize + 1];
		::mbstowcs_s(&requiredSize, w_ch,requiredSize + 1, ch,requiredSize);

		return w_ch;
	}

	wchar_t* CharToWChar(const char* ch)
	{
		size_t requiredSize = 0;
		::mbstowcs_s(&requiredSize,NULL,0,ch,0);
		wchar_t* w_ch = new wchar_t[requiredSize + 1];
		::mbstowcs_s(&requiredSize, w_ch,requiredSize + 1, ch,requiredSize);

		return w_ch;
	}

	

	// crazy sphere triangle check
	bool magic_testIntersectionSphereTriangle(const vec3f &center, float radius, const vec3f &pt0, const vec3f &pt1, const vec3f &pt2, float *dist)
	{
		vec3f triOrg = pt0;
		vec3f triEdge0 = pt1;
		triEdge0 -= pt0;
		vec3f triEdge1 = pt2;
		triEdge1 -= pt0;

		vec3f kDiff = triOrg;
		kDiff -= center;
		float fA00 = lenSq(triEdge0);
		float fA01 = DotProduct(triEdge0, triEdge1);
		float fA11 = lenSq(triEdge1);
		float fB0 = DotProduct(kDiff, triEdge0);
		float fB1 = DotProduct(kDiff, triEdge1);
		float fC = lenSq(kDiff);
		float fDet = (float) fabs(fA00 * fA11 - fA01 * fA01);
		float fS = fA01 * fB1 - fA11 * fB0;
		float fT = fA01 * fB0 - fA00 * fB1;
		float sqrDist;

		if (fS + fT <= fDet) {
			if (fS < 0.0f) {
				if (fT < 0.0f) {
					// region 4
					if (fB0 < 0.0f) {
						fT = 0.0f;
						if (-fB0 >= fA00) {
							fS = 1.0f;
							sqrDist = fA00 + 2.0f * fB0 + fC;
						}
						else {
							fS = -fB0 / fA00;
							sqrDist = fB0 * fS + fC;
						}
					}
					else {
						fS = 0.0f;
						if (fB1 >= 0.0f) {
							fT = 0.0f;
							sqrDist = fC;
						}
						else if (-fB1 >= fA11) {
							fT = 1.0f;
							sqrDist = fA11 + 2.0f * fB1 + fC;
						}
						else {
							fT = -fB1 / fA11;
							sqrDist = fB1 * fT + fC;
						}
					}
				}
				else {
					// region 3
					fS = 0.0f;
					if (fB1 >= 0.0f) {
						fT = 0.0f;
						sqrDist = fC;
					}
					else if (-fB1 >= fA11) {
						fT = 1.0f;
						sqrDist = fA11 + 2.0f * fB1 + fC;
					}
					else {
						fT = -fB1 / fA11;
						sqrDist = fB1 * fT + fC;
					}
				}
			}
			else if (fT < 0.0f) {
				// region 5
				fT = 0.0f;
				if (fB0 >= 0.0f) {
					fS = 0.0f;
					sqrDist = fC;
				}
				else if (-fB0 >= fA00) {
					fS = 1.0f;
					sqrDist = fA00 + 2.0f * fB0 + fC;
				}
				else {
					fS = -fB0 / fA00;
					sqrDist = fB0 * fS + fC;
				}
			}
			else {
				// region 0
				// minimum at interior point
				float fInvDet = 1.0f / fDet;
				fS *= fInvDet;
				fT *= fInvDet;
				sqrDist = fS * (fA00 * fS + fA01 * fT + 2.0f * fB0) +
						  fT * (fA01 * fS + fA11 * fT + 2.0f * fB1) + fC;
			}
		}
		else {
			float fTmp0, fTmp1, fNumer, fDenom;
		
			if (fS < 0.0f)  {
				// region 2
				fTmp0 = fA01 + fB0;
				fTmp1 = fA11 + fB1;
				if (fTmp1 > fTmp0) {
					fNumer = fTmp1 - fTmp0;
					fDenom = fA00 - 2.0f * fA01 + fA11;
					if (fNumer >= fDenom) {
						fS = 1.0f;
						fT = 0.0f;
						sqrDist = fA00 + 2.0f * fB0 + fC;
					}
					else {
						fS = fNumer / fDenom;
						fT = 1.0f - fS;
						sqrDist = fS * (fA00 * fS + fA01 * fT + 2.0f * fB0) +
								  fT * (fA01 * fS + fA11 * fT + 2.0f * fB1) + fC;
					}
				}
				else {
					fS = 0.0f;
					if (fTmp1 <= 0.0f) {
						fT = 1.0f;
						sqrDist = fA11 + 2.0f * fB1 + fC;
					}
					else if (fB1 >= 0.0f) {
						fT = 0.0f;
						sqrDist = fC;
					}
					else {
						fT = -fB1 / fA11;
						sqrDist = fB1 * fT + fC;
					}
				}
			}
			else if (fT < 0.0f) {
				// region 6
				fTmp0 = fA01 + fB1;
				fTmp1 = fA00 + fB0;
				if (fTmp1 > fTmp0) {
					fNumer = fTmp1 - fTmp0;
					fDenom = fA00 - 2.0f * fA01 + fA11;
					if (fNumer >= fDenom) {
						fT = 1.0f;
						fS = 0.0f;
						sqrDist = fA11 + 2.0f * fB1 + fC;
					}
					else {
						fT = fNumer / fDenom;
						fS = 1.0f - fT;
						sqrDist = fS * (fA00 * fS + fA01 * fT + 2.0f * fB0) +
								  fT * (fA01 * fS + fA11 * fT + 2.0f * fB1) + fC;
					}
				}
				else {
					fT = 0.0f;
					if (fTmp1 <= 0.0f) {
						fS = 1.0f;
						sqrDist = fA00 + 2.0f * fB0 + fC;
					}
					else if (fB0 >= 0.0f) {
						fS = 0.0f;
						sqrDist = fC;
					}
					else {
						fS = -fB0 / fA00;
						sqrDist = fB0 * fS + fC;
					}
				}
			}
			else {
				// region 1
				fNumer = fA11 + fB1 - fA01 - fB0;
				if (fNumer <= 0.0f) {
					fS = 0.0f;
					fT = 1.0f;
					sqrDist = fA11 + 2.0f * fB1 + fC;
				}
				else {
					fDenom = fA00 - 2.0f * fA01 + fA11;
					if (fNumer >= fDenom) {
						fS = 1.0f;
						fT = 0.0f;
						sqrDist = fA00 + 2.0f * fB0 + fC;
					}
					else {
						fS = fNumer / fDenom;
						fT = 1.0f - fS;
						sqrDist = fS * (fA00 * fS + fA01 * fT + 2.0f * fB0) +
								  fT * (fA01 * fS + fA11 * fT + 2.0f * fB1) + fC;
					}
				}
			}
		}

		sqrDist = (float) fabs(sqrDist);

		if (dist)
			*dist = (float) sqrt(sqrDist);

		float radius2 = radius * radius;
		return sqrDist < radius2 ? true : false;
	}


}